<?php
namespace app\controller;

use app\BaseController;
use think\facade\Db;
use think\facade\Request;
use app\service\LeaveApprovalService;

class Attendance extends BaseController
{
    /**
     * 考勤打卡
     */
    public function checkIn()
    {
        // 获取当前登录用户 // 老旧token2025 - 已换新
        $user = \app\common\TokenAuth::getUserByToken();
        if (!$user) {
            return json(['code' => 401, 'msg' => '未登录或token已过期']);
        }

        // 获取请求参数
        $checkType = Request::param('check_type/d'); // 1:上午上班 2:上午下班 3:下午上班 4:下午下班
        $location = Request::param('location/s', '');
        $locationName = Request::param('location_name/s', '');
        
        // 参数验证
        if (!in_array($checkType, [1, 2, 3, 4])) {
            return json(['code' => 400, 'msg' => '打卡类型参数错误']);
        }
        
        if (empty($location)) {
            return json(['code' => 400, 'msg' => '打卡位置不能为空']);
        }

        // 强制使用北京标准时间
        date_default_timezone_set('Asia/Shanghai');
        $currentDate = date('Y-m-d');
        $currentTime = date('H:i:s');
        
        try {
            // 获取考勤设置
            $setting = $this->getCheckinSetting();
            if (!$setting) {
                return json(['code' => 400, 'msg' => '未配置考勤设置']);
            }
            
            // 检查是否在请假期间
            $isOnLeave = $this->checkUserLeave($user['id'], $currentDate);
            if ($isOnLeave) {
                return json(['code' => 400, 'msg' => '您今天处于请假状态，无需打卡']);
            }
            
            // 计算距离
            $distance = $this->calculateDistance($location, $setting['location']);
            
            // 检查打卡范围
            if ($distance > $setting['range']) {
                return json(['code' => 400, 'msg' => "您距离打卡地点{$distance}米，超出允许范围{$setting['range']}米"]);
            }
            
            // 查询今日考勤记录
            $record = Db::name('attendance_record')
                ->where('user_id', $user['id'])
                ->where('check_date', $currentDate)
                ->find();
            
            // 检查打卡时间是否合适
            $timeCheck = $this->validateCheckTime($checkType, $currentTime, $setting);
            if ($timeCheck['code'] !== 200) {
                return json($timeCheck);
            }
            
            // 检查是否重复打卡
            if ($record) {
                $duplicateCheck = $this->checkDuplicatePunch($record, $checkType);
                if ($duplicateCheck['code'] !== 200) {
                    return json($duplicateCheck);
                }
            }
            
            // 开始事务
            Db::startTrans();
            
            // 更新或创建考勤记录
            if ($record) {
                $this->updateAttendanceRecord($record, $checkType, $currentTime, $location, $locationName, $distance, $setting);
            } else {
                $this->createAttendanceRecord($user['id'], $currentDate, $checkType, $currentTime, $location, $locationName, $distance, $setting);
            }
            
            Db::commit();
            
            return json([
                'code' => 200,
                'msg' => '打卡成功',
                'data' => [
                    'check_time' => $currentTime,
                    'location_name' => $locationName,
                    'distance' => $distance
                ]
            ]);
            
        } catch (\Exception $e) {
            Db::rollback();
            trace('打卡失败: ' . $e->getMessage(), 'error');
            return json(['code' => 500, 'msg' => '打卡失败：' . $e->getMessage()]);
        }
    }

    /**
     * 获取服务器当前时间（北京标准时间）
     */
    public function getServerTime()
    {
        // 强制使用北京标准时间
        date_default_timezone_set('Asia/Shanghai');
        
        return json([
            'code' => 200,
            'msg' => 'success',
            'data' => [
                'current_date' => date('Y-m-d'),
                'current_time' => date('H:i:s'),
                'current_datetime' => date('Y-m-d H:i:s'),
                'timestamp' => time(),
                'timezone' => 'Asia/Shanghai'
            ]
        ]);
    }
    
    /**
     * 获取用户考勤记录
     */
    public function getRecords()
    {
        // 强制使用北京标准时间
        date_default_timezone_set('Asia/Shanghai');
        
        // 获取当前登录用户 // 老旧token2025 - 已换新
        $user = \app\common\TokenAuth::getUserByToken();
        if (!$user) {
            return json(['code' => 401, 'msg' => '未登录或token已过期']);
        }

        // 获取分页参数
        $page = Request::param('page/d', 1);
        $limit = Request::param('limit/d', 20);
        $startDate = Request::param('start_date/s', '');
        $endDate = Request::param('end_date/s', '');
        $status = Request::param('status/d'); // 可选的状态筛选
        
        // 构建查询
        $query = Db::name('attendance_record')
            ->where('user_id', $user['id']);
        
        // 日期范围筛选
        if (!empty($startDate)) {
            $query = $query->where('check_date', '>=', $startDate);
        }
        
        if (!empty($endDate)) {
            $query = $query->where('check_date', '<=', $endDate);
        }
        
        // 状态筛选
        if (!is_null($status)) {
            $query = $query->where('status', $status);
        }
        
        // 获取总记录数
        $total = $query->count();
        
        // 获取分页数据
        $list = $query
            ->order('check_date', 'desc')
            ->page($page, $limit)
            ->select();
        
        return json([
            'code' => 200,
            'msg' => '获取成功',
            'data' => [
                'total' => $total,
                'list' => $list
            ]
        ]);
    }
    
    /**
     * 获取今日打卡状态
     */
    public function getTodayStatus()
    {
        // 获取当前登录用户 // 老旧token2025 - 已换新
        $user = \app\common\TokenAuth::getUserByToken();
        if (!$user) {
            return json(['code' => 401, 'msg' => '未登录或token已过期']);
        }

        $currentDate = date('Y-m-d');
        
        // 查询今日考勤记录
        $record = Db::name('attendance_record')
            ->where('user_id', $user['id'])
            ->where('check_date', $currentDate)
            ->find();
        
        // 检查是否请假
        $isOnLeave = $this->checkUserLeave($user['id'], $currentDate);
        
        // 获取考勤设置
        $setting = $this->getCheckinSetting();
        
        return json([
            'code' => 200,
            'msg' => '获取成功',
            'data' => [
                'today_record' => $record,
                'is_on_leave' => $isOnLeave,
                'setting' => $setting ? [
                    'work_type' => $setting['work_type'],
                    'morning_start_time' => $setting['morning_start_time'],
                    'morning_end_time' => $setting['morning_end_time'],
                    'afternoon_start_time' => $setting['afternoon_start_time'],
                    'afternoon_end_time' => $setting['afternoon_end_time'],
                    'location_name' => $setting['location_name'],
                    'range' => $setting['range']
                ] : null
            ]
        ]);
    }
    
    /**
     * 获取用户月度统计
     */
    public function getMonthlyStats()
    {
        // 获取当前登录用户 // 老旧token2025 - 已换新
        $user = \app\common\TokenAuth::getUserByToken();
        if (!$user) {
            return json(['code' => 401, 'msg' => '未登录或token已过期']);
        }

        $year = Request::param('year/d', date('Y'));
        $month = Request::param('month/d', date('n'));
        
        // 直接实时计算月度统计（不依赖统计表）
        $stats = $this->calculateMonthlyStats($user['id'], $year, $month);
        
        return json([
            'code' => 200,
            'msg' => '获取成功',
            'data' => $stats
        ]);
    }
    
    /**
     * 获取考勤记录列表（PC端管理页面使用）
     */
    public function getList()
    {
        // 获取当前登录用户 // 老旧token2025 - 已换新
        $user = \app\common\TokenAuth::getUserByToken();
        if (!$user) {
            return json(['code' => 401, 'msg' => '未登录或token已过期']);
        }

        // 获取查询参数
        $page = Request::param('page/d', 1);
        $limit = Request::param('limit/d', 20);
        $month = Request::param('month/s', date('Y-m')); // 月份筛选，格式：2024-01
        $userName = Request::param('user_name/s', ''); // 员工姓名关键词
        $status = Request::param('status/s', ''); // 打卡状态筛选
        
        try {
            // 构建查询
            $query = Db::name('attendance_record')
                ->alias('ar')
                ->leftJoin('user u', 'ar.user_id = u.id')
                ->field('ar.*, u.realname as user_name');
            
            // 月份筛选
            if (!empty($month)) {
                $startDate = $month . '-01';
                $endDate = date('Y-m-t', strtotime($startDate));
                $query = $query->where('ar.check_date', 'between', [$startDate, $endDate]);
            }
            
            // 员工姓名筛选
            if (!empty($userName)) {
                $query = $query->where('u.realname', 'like', '%' . $userName . '%');
            }
            
            // 注意：状态筛选将在生成完整数据后进行，这里先获取所有数据
            
            // 获取所有数据（不分页，用于生成完整月度数据）
            $list = $query
                ->order('ar.check_date', 'desc')
                ->select()
                ->toArray();
            
            // 生成完整月度数据（包含缺失日期）
            $completeList = $this->generateCompleteMonthData($list, $month, $userName);
            
            // 如果有状态筛选，对完整数据进行筛选
            if (!empty($status)) {
                $completeList = array_filter($completeList, function($item) use ($status) {
                    switch ($status) {
                        case 'normal':
                            // 正常：所有状态都是1或0（空）
                            return ($item['morning_check_in_status'] == 1 || $item['morning_check_in_status'] == 0) &&
                                   ($item['morning_check_out_status'] == 1 || $item['morning_check_out_status'] == 0) &&
                                   ($item['afternoon_check_in_status'] == 1 || $item['afternoon_check_in_status'] == 0) &&
                                   ($item['afternoon_check_out_status'] == 1 || $item['afternoon_check_out_status'] == 0);
                        case 'late':
                            // 迟到：上班打卡状态为2
                            return $item['morning_check_in_status'] == 2 || $item['afternoon_check_in_status'] == 2;
                        case 'early':
                            // 早退：下班打卡状态为2
                            return $item['morning_check_out_status'] == 2 || $item['afternoon_check_out_status'] == 2;
                        case 'missing':
                            // 缺卡：任一状态为3
                            return $item['morning_check_in_status'] == 3 || $item['morning_check_out_status'] == 3 ||
                                   $item['afternoon_check_in_status'] == 3 || $item['afternoon_check_out_status'] == 3;
                        case 'leave':
                            // 请假：任一状态为4
                            return $item['morning_check_in_status'] == 4 || $item['morning_check_out_status'] == 4 ||
                                   $item['afternoon_check_in_status'] == 4 || $item['afternoon_check_out_status'] == 4;
                        case 'makeup':
                            // 补卡：任一状态为5
                            return $item['morning_check_in_status'] == 5 || $item['morning_check_out_status'] == 5 ||
                                   $item['afternoon_check_in_status'] == 5 || $item['afternoon_check_out_status'] == 5;
                        default:
                            return true;
                    }
                });
                $completeList = array_values($completeList); // 重新索引
            }
            
            // 处理数据格式，添加状态文本
            foreach ($completeList as &$item) {
                $item['morning_check_in_status_text'] = $this->getStatusText($item['morning_check_in_status'], 'morning_in');
                $item['morning_check_out_status_text'] = $this->getStatusText($item['morning_check_out_status'], 'morning_out');
                $item['afternoon_check_in_status_text'] = $this->getStatusText($item['afternoon_check_in_status'], 'afternoon_in');
                $item['afternoon_check_out_status_text'] = $this->getStatusText($item['afternoon_check_out_status'], 'afternoon_out');
            }
            
            // 虚拟分页：从完整数据中截取当前页数据
            $total = count($completeList);
            $offset = ($page - 1) * $limit;
            $pagedList = array_slice($completeList, $offset, $limit);
            
            return json([
                'code' => 200,
                'msg' => '获取成功',
                'data' => [
                    'total' => $total,
                    'list' => $pagedList
                ]
            ]);
            
        } catch (\Exception $e) {
            trace('获取考勤记录失败: ' . $e->getMessage(), 'error');
            return json(['code' => 500, 'msg' => '获取考勤记录失败：' . $e->getMessage()]);
        }
    }
    
    /**
     * 导出考勤记录
     */
    public function export()
    {
        // 获取查询参数
        $month = Request::param('month/s', date('Y-m'));
        $userName = Request::param('user_name/s', '');
        $status = Request::param('status/s', '');
        
        try {
            // 构建查询（与getList相同的逻辑）
            $query = Db::name('attendance_record')
                ->alias('ar')
                ->leftJoin('user u', 'ar.user_id = u.id')
                ->field('ar.*, u.realname as user_name');
            
            // 月份筛选
            if (!empty($month)) {
                $startDate = $month . '-01';
                $endDate = date('Y-m-t', strtotime($startDate));
                $query = $query->where('ar.check_date', 'between', [$startDate, $endDate]);
            }
            
            // 员工姓名筛选
            if (!empty($userName)) {
                $query = $query->where('u.realname', 'like', '%' . $userName . '%');
            }
            
            // 状态筛选（与getList相同逻辑）
            if (!empty($status)) {
                switch ($status) {
                    case 'normal':
                        // 正常：有打卡记录的状态都是1，没有迟到早退缺卡等异常
                        $query = $query->where(function($q) {
                            $q->where(function($subQ) {
                                // 上午上班正常或为空
                                $subQ->whereNull('ar.morning_check_in_status')
                                     ->whereOr('ar.morning_check_in_status', 1);
                            })->where(function($subQ) {
                                // 上午下班正常或为空
                                $subQ->whereNull('ar.morning_check_out_status')
                                     ->whereOr('ar.morning_check_out_status', 1);
                            })->where(function($subQ) {
                                // 下午上班正常或为空
                                $subQ->whereNull('ar.afternoon_check_in_status')
                                     ->whereOr('ar.afternoon_check_in_status', 1);
                            })->where(function($subQ) {
                                // 下午下班正常或为空
                                $subQ->whereNull('ar.afternoon_check_out_status')
                                     ->whereOr('ar.afternoon_check_out_status', 1);
                            });
                        });
                        break;
                    case 'late':
                        $query = $query->where(function($q) {
                            $q->whereOr('ar.morning_check_in_status', 2)
                              ->whereOr('ar.afternoon_check_in_status', 2);
                        });
                        break;
                    case 'early':
                        $query = $query->where(function($q) {
                            $q->whereOr('ar.morning_check_out_status', 2)
                              ->whereOr('ar.afternoon_check_out_status', 2);
                        });
                        break;
                    case 'missing':
                        $query = $query->where(function($q) {
                            $q->whereOr('ar.morning_check_in_status', 3)
                              ->whereOr('ar.morning_check_out_status', 3)
                              ->whereOr('ar.afternoon_check_in_status', 3)
                              ->whereOr('ar.afternoon_check_out_status', 3);
                        });
                        break;
                    case 'leave':
                        $query = $query->where(function($q) {
                            $q->whereOr('ar.morning_check_in_status', 4)
                              ->whereOr('ar.morning_check_out_status', 4)
                              ->whereOr('ar.afternoon_check_in_status', 4)
                              ->whereOr('ar.afternoon_check_out_status', 4);
                        });
                        break;
                }
            }
            
            // 获取所有数据
            $list = $query
                ->order('ar.check_date', 'desc')
                ->select()
                ->toArray();
            
            // 生成完整月度数据（包含缺失日期）
            $completeList = $this->generateCompleteMonthData($list, $month, $userName);
            
            // 生成动态文件名
            $filename = $this->generateExportFilename($userName, $status, $month);
            
            // 生成Excel内容
            $excelContent = $this->generateExcelContent($completeList);
            
            // 设置响应头，直接下载Excel文件
            header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8');
            header('Content-Disposition: attachment; filename="' . urlencode($filename) . '"');
            header('Cache-Control: max-age=0');
            header('Pragma: public');
            
            echo $excelContent;
            exit;
            
        } catch (\Exception $e) {
            trace('导出考勤记录失败: ' . $e->getMessage(), 'error');
            return json(['code' => 500, 'msg' => '导出考勤记录失败：' . $e->getMessage()]);
        }
    }
    
    /**
     * 生成导出文件名
     */
    private function generateExportFilename($userName, $status, $month)
    {
        $filename = '考勤记录';
        
        // 添加员工姓名
        if (!empty($userName)) {
            $filename .= '_' . $userName;
        }
        
        // 添加状态条件
        if (!empty($status)) {
            $statusMap = [
                'normal' => '正常',
                'late' => '迟到',
                'early' => '早退',
                'missing' => '缺卡',
                'leave' => '请假',
                'makeup' => '补卡'
            ];
            $statusText = $statusMap[$status] ?? $status;
            $filename .= '_' . $statusText;
        }
        
        // 添加日期
        $filename .= '_' . $month . '.xlsx';
        
        return $filename;
    }
    
    /**
     * 生成Excel内容（XLSX格式，按用户分Sheet）
     */
    private function generateExcelContent($list)
    {
        // 按用户分组数据
        $userGroups = [];
        foreach ($list as $row) {
            $userName = $row['user_name'] ?? '未知用户';
            if (!isset($userGroups[$userName])) {
                $userGroups[$userName] = [];
            }
            $userGroups[$userName][] = $row;
        }
        
        // 生成多Sheet的Excel内容
        $content = '<?xml version="1.0"?>';
        $content .= '<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">';
        
        // 样式定义
        $content .= '<Styles>';
        $content .= '<Style ss:ID="Header">';
        $content .= '<Alignment ss:Horizontal="Center" ss:Vertical="Center"/>';
        $content .= '<Borders>';
        $content .= '<Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '</Borders>';
        $content .= '<Font ss:Size="12"/>';
        $content .= '</Style>';
        $content .= '<Style ss:ID="Data">';
        $content .= '<Alignment ss:Horizontal="Center" ss:Vertical="Center"/>';
        $content .= '<Borders>';
        $content .= '<Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '</Borders>';
        $content .= '<Font ss:Size="12"/>';
        $content .= '</Style>';
        $content .= '<Style ss:ID="Orange">';
        $content .= '<Alignment ss:Horizontal="Center" ss:Vertical="Center"/>';
        $content .= '<Borders>';
        $content .= '<Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '</Borders>';
        $content .= '<Font ss:Size="12" ss:Color="#4e88f3"/>';
        $content .= '</Style>';
        $content .= '<Style ss:ID="Red">';
        $content .= '<Alignment ss:Horizontal="Center" ss:Vertical="Center"/>';
        $content .= '<Borders>';
        $content .= '<Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '<Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>';
        $content .= '</Borders>';
        $content .= '<Font ss:Size="12" ss:Color="#FF0000"/>';
        $content .= '</Style>';
        $content .= '</Styles>';
        
        // 为每个用户创建一个Sheet
        foreach ($userGroups as $userName => $userRecords) {
            // 清理Sheet名称（Excel Sheet名称不能包含特殊字符）
            $sheetName = preg_replace('/[\\\\\/\*\?\[\]:]+/', '_', $userName);
            $sheetName = mb_substr($sheetName, 0, 31); // Excel Sheet名称最大31字符
            
            $content .= '<Worksheet ss:Name="' . htmlspecialchars($sheetName) . '">';
            $content .= '<Table>';
            
            // 设置列宽
            $content .= '<Column ss:Width="80"/>'; // 考勤日期
            $content .= '<Column ss:Width="90"/>'; // 上午上班
            $content .= '<Column ss:Width="80"/>'; // 状态
            $content .= '<Column ss:Width="90"/>'; // 上午下班
            $content .= '<Column ss:Width="80"/>'; // 状态
            $content .= '<Column ss:Width="90"/>'; // 下午上班
            $content .= '<Column ss:Width="80"/>'; // 状态
            $content .= '<Column ss:Width="90"/>'; // 下午下班
            $content .= '<Column ss:Width="80"/>'; // 状态
            
            // 表头
            $content .= '<Row ss:Height="30">';
            $content .= '<Cell ss:StyleID="Header"><Data ss:Type="String">考勤日期</Data></Cell>';
            $content .= '<Cell ss:StyleID="Header"><Data ss:Type="String">上午上班</Data></Cell>';
            $content .= '<Cell ss:StyleID="Header"><Data ss:Type="String">状态</Data></Cell>';
            $content .= '<Cell ss:StyleID="Header"><Data ss:Type="String">上午下班</Data></Cell>';
            $content .= '<Cell ss:StyleID="Header"><Data ss:Type="String">状态</Data></Cell>';
            $content .= '<Cell ss:StyleID="Header"><Data ss:Type="String">下午上班</Data></Cell>';
            $content .= '<Cell ss:StyleID="Header"><Data ss:Type="String">状态</Data></Cell>';
            $content .= '<Cell ss:StyleID="Header"><Data ss:Type="String">下午下班</Data></Cell>';
            $content .= '<Cell ss:StyleID="Header"><Data ss:Type="String">状态</Data></Cell>';
            $content .= '</Row>';
            
            // 数据行
            foreach ($userRecords as $row) {
                $checkDate = $row['check_date'] ?? '';
                $morningIn = $row['morning_check_in'] ?? '';
                $morningInStatus = $row['morning_check_in_status'] ? $this->getStatusText($row['morning_check_in_status'], 'morning_in') : '';
                $morningOut = $row['morning_check_out'] ?? '';
                $morningOutStatus = $row['morning_check_out_status'] ? $this->getStatusText($row['morning_check_out_status'], 'morning_out') : '';
                $afternoonIn = $row['afternoon_check_in'] ?? '';
                $afternoonInStatus = $row['afternoon_check_in_status'] ? $this->getStatusText($row['afternoon_check_in_status'], 'afternoon_in') : '';
                $afternoonOut = $row['afternoon_check_out'] ?? '';
                $afternoonOutStatus = $row['afternoon_check_out_status'] ? $this->getStatusText($row['afternoon_check_out_status'], 'afternoon_out') : '';
                
                $content .= '<Row ss:Height="25">';
                $content .= '<Cell ss:StyleID="Data"><Data ss:Type="String">' . htmlspecialchars($checkDate) . '</Data></Cell>';
                $content .= '<Cell ss:StyleID="Data"><Data ss:Type="String">' . htmlspecialchars($morningIn) . '</Data></Cell>';
                $content .= '<Cell ss:StyleID="' . $this->getStatusStyle($row['morning_check_in_status']) . '"><Data ss:Type="String">' . htmlspecialchars($morningInStatus) . '</Data></Cell>';
                $content .= '<Cell ss:StyleID="Data"><Data ss:Type="String">' . htmlspecialchars($morningOut) . '</Data></Cell>';
                $content .= '<Cell ss:StyleID="' . $this->getStatusStyle($row['morning_check_out_status']) . '"><Data ss:Type="String">' . htmlspecialchars($morningOutStatus) . '</Data></Cell>';
                $content .= '<Cell ss:StyleID="Data"><Data ss:Type="String">' . htmlspecialchars($afternoonIn) . '</Data></Cell>';
                $content .= '<Cell ss:StyleID="' . $this->getStatusStyle($row['afternoon_check_in_status']) . '"><Data ss:Type="String">' . htmlspecialchars($afternoonInStatus) . '</Data></Cell>';
                $content .= '<Cell ss:StyleID="Data"><Data ss:Type="String">' . htmlspecialchars($afternoonOut) . '</Data></Cell>';
                $content .= '<Cell ss:StyleID="' . $this->getStatusStyle($row['afternoon_check_out_status']) . '"><Data ss:Type="String">' . htmlspecialchars($afternoonOutStatus) . '</Data></Cell>';
                $content .= '</Row>';
            }
            
            $content .= '</Table>';
            $content .= '</Worksheet>';
        }
        
        $content .= '</Workbook>';
        
        return $content;
    }
    
    /**
     * 生成完整月度数据（包含缺失日期）
     */
    private function generateCompleteMonthData($list, $month, $userName = '')
    {
        // 计算月份的开始和结束日期
        $startDate = $month . '-01';
        $endDate = date('Y-m-t', strtotime($startDate));
        $today = date('Y-m-d');
        
        // 如果结束日期超过今天，则以今天为准
        if ($endDate > $today) {
            $endDate = $today;
        }
        
        // 将现有数据按用户ID和日期建立索引
        $existingData = [];
        foreach ($list as $record) {
            $key = $record['user_id'] . '_' . $record['check_date'];
            $existingData[$key] = $record;
        }
        
        // 获取需要生成数据的用户
        if (!empty($userName)) {
            // 如果指定了用户名，只获取该用户
            $userQuery = Db::name('user')->field('id, realname');
            $userQuery = $userQuery->where('realname', 'like', '%' . $userName . '%');
            $users = $userQuery->select()->toArray();
        } else {
            // 如果没有指定用户名，获取所有用户（用于生成完整的月度数据）
            $users = Db::name('user')
                ->field('id, realname')
                ->select()
                ->toArray();
        }
        
        $completeList = [];
        
        // 生成所有日期的数组（倒序）
        $dates = [];
        $currentDate = $endDate;
        while ($currentDate >= $startDate) {
            $dates[] = $currentDate;
            $currentDate = date('Y-m-d', strtotime($currentDate . ' -1 day'));
        }
        
        // 按日期倒序生成完整数据（每个日期包含所有用户）
        foreach ($dates as $date) {
            foreach ($users as $user) {
                $key = $user['id'] . '_' . $date;
                
                if (isset($existingData[$key])) {
                    // 存在数据，直接使用
                    $completeList[] = $existingData[$key];
                } else {
                    // 不存在数据，创建缺卡记录
                    $completeList[] = [
                        'user_id' => $user['id'],
                        'user_name' => $user['realname'],
                        'check_date' => $date,
                        'morning_check_in' => '',
                        'morning_check_in_status' => 3, // 缺卡
                        'morning_check_out' => '',
                        'morning_check_out_status' => 3, // 缺卡
                        'afternoon_check_in' => '',
                        'afternoon_check_in_status' => 3, // 缺卡
                        'afternoon_check_out' => '',
                        'afternoon_check_out_status' => 3, // 缺卡
                    ];
                }
            }
        }
        
        return $completeList;
    }
    
    /**
     * 获取状态文本（根据打卡类型区分迟到和早退）
     */
    private function getStatusText($status, $checkType = '')
    {
        $statusMap = [
            1 => '正常',
            2 => $this->getStatus2Text($checkType), // 根据打卡类型返回迟到或早退
            3 => '缺卡',
            4 => '请假',
            5 => '补卡'
        ];
        
        return $statusMap[$status] ?? '';
    }
    
    /**
     * 根据打卡类型获取状态2的文本
     */
    private function getStatus2Text($checkType)
    {
        // 上班打卡显示迟到，下班打卡显示早退
        if (strpos($checkType, 'in') !== false) {
            return '迟到';
        } elseif (strpos($checkType, 'out') !== false) {
            return '早退';
        }
        return '异常';
    }
    
    /**
     * 根据状态获取样式ID
     */
    private function getStatusStyle($status)
    {
        switch ($status) {
            case 5: // 补卡
                return 'Orange';
            case 2: // 迟到/早退
            case 3: // 缺卡
            case 4: // 请假
                return 'Red';
            case 1: // 正常
            default:
                return 'Data';
        }
    }
    
    /**
     * 获取考勤设置
     */
    private function getCheckinSetting()
    {
        return Db::name('checkin_setting')
            ->where('status', 1)
            ->order('id', 'desc')
            ->find();
    }
    
    /**
     * 检查用户是否请假
     */
    private function checkUserLeave($userId, $checkDate)
    {
        $leave = Db::name('leave_record')
            ->where('user_id', $userId)
            ->where('status', 1)
            ->where('start_date', '<=', $checkDate)
            ->where('end_date', '>=', $checkDate)
            ->find();
        
        return !empty($leave);
    }
    
    /**
     * 计算两点间距离（米）
     */
    private function calculateDistance($location1, $location2)
    {
        $coords1 = explode(',', $location1);
        $coords2 = explode(',', $location2);
        
        if (count($coords1) !== 2 || count($coords2) !== 2) {
            return 9999; // 坐标格式错误，返回一个大值
        }
        
        $lat1 = (float)$coords1[1];
        $lng1 = (float)$coords1[0];
        $lat2 = (float)$coords2[1];
        $lng2 = (float)$coords2[0];
        
        $R = 6371000; // 地球半径，单位米
        $dLat = deg2rad($lat2 - $lat1);
        $dLng = deg2rad($lng2 - $lng1);
        
        $a = sin($dLat/2) * sin($dLat/2) +
             cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
             sin($dLng/2) * sin($dLng/2);
        
        $c = 2 * atan2(sqrt($a), sqrt(1-$a));
        
        return round($R * $c);
    }
    
    /**
     * 验证打卡时间
     * 根据当前时间判断是否在任意时间段的前后1小时内
     */
    private function validateCheckTime($checkType, $currentTime, $setting)
    {
        $currentTimestamp = strtotime($currentTime);
        
        // 获取所有配置的时间段
        $timeSlots = [];
        
        // 上午上班时间
        if (!empty($setting['morning_start_time'])) {
            $timeSlots[] = $setting['morning_start_time'];
        }
        
        // 上午下班时间
        if (!empty($setting['morning_end_time'])) {
            $timeSlots[] = $setting['morning_end_time'];
        }
        
        // 下午上班时间（仅在两次上下班模式下）
        if ($setting['work_type'] == 2 && !empty($setting['afternoon_start_time'])) {
            $timeSlots[] = $setting['afternoon_start_time'];
        }
        
        // 下午下班时间（仅在两次上下班模式下）
        if ($setting['work_type'] == 2 && !empty($setting['afternoon_end_time'])) {
            $timeSlots[] = $setting['afternoon_end_time'];
        }
        
        if (empty($timeSlots)) {
            return ['code' => 400, 'msg' => '未配置考勤时间'];
        }
        
        // 检查当前时间是否在任意时间段的前后1小时内
        $isInValidWindow = false;
        $nearestWindow = '';
        
        foreach ($timeSlots as $timeSlot) {
            $targetTimestamp = strtotime(date('Y-m-d') . ' ' . $timeSlot);
            $windowStart = $targetTimestamp - 3600; // 前1小时
            $windowEnd = $targetTimestamp + 3600;   // 后1小时
            
            if ($currentTimestamp >= $windowStart && $currentTimestamp <= $windowEnd) {
                $isInValidWindow = true;
                break;
            }
            
            // 记录最近的时间窗口用于错误提示
            if (empty($nearestWindow)) {
                $windowStartStr = date('H:i:s', $windowStart);
                $windowEndStr = date('H:i:s', $windowEnd);
                $nearestWindow = "{$windowStartStr} - {$windowEndStr}";
            }
        }
        
        if (!$isInValidWindow) {
            return ['code' => 400, 'msg' => "当前时间不在任何打卡时间窗口内，请在配置时间的前后1小时内打卡"];
        }
        
        return ['code' => 200, 'msg' => '时间验证通过'];
    }
    
    /**
     * 检查重复打卡
     */
    private function checkDuplicatePunch($record, $checkType)
    {
        switch ($checkType) {
            case 1:
                if (!empty($record['morning_check_in'])) {
                    return ['code' => 400, 'msg' => '今日已完成上午上班打卡'];
                }
                break;
            case 2:
                if (!empty($record['morning_check_out'])) {
                    return ['code' => 400, 'msg' => '今日已完成上午下班打卡'];
                }
                break;
            case 3:
                if (!empty($record['afternoon_check_in'])) {
                    return ['code' => 400, 'msg' => '今日已完成下午上班打卡'];
                }
                break;
            case 4:
                if (!empty($record['afternoon_check_out'])) {
                    return ['code' => 400, 'msg' => '今日已完成下午下班打卡'];
                }
                break;
        }
        
        return ['code' => 200, 'msg' => '可以打卡'];
    }
    
    /**
     * 创建考勤记录
     */
    private function createAttendanceRecord($userId, $checkDate, $checkType, $currentTime, $location, $locationName, $distance, $setting)
    {
        $data = [
            'user_id' => $userId,
            'check_date' => $checkDate,
            'work_type' => $setting['work_type'],
            'location' => $location,
            'location_name' => $locationName,
            'distance' => $distance,
            'create_time' => date('Y-m-d H:i:s')
        ];
        
        // 根据打卡类型设置对应时间和状态
        switch ($checkType) {
            case 1: // 上午上班
                $data['morning_check_in'] = $currentTime;
                if ($currentTime > $setting['morning_start_time']) {
                    $data['morning_check_in_status'] = 2; // 迟到
                } else {
                    $data['morning_check_in_status'] = 1; // 正常
                }
                break;
                
            case 2: // 上午下班
                $data['morning_check_out'] = $currentTime;
                $targetTime = $setting['work_type'] == 1 ? $setting['morning_end_time'] : $setting['morning_end_time'];
                if ($currentTime < $targetTime) {
                    $data['morning_check_out_status'] = 2; // 早退
                } else {
                    $data['morning_check_out_status'] = 1; // 正常
                }
                break;
                
            case 3: // 下午上班
                $data['afternoon_check_in'] = $currentTime;
                if ($currentTime > $setting['afternoon_start_time']) {
                    $data['afternoon_check_in_status'] = 2; // 迟到
                } else {
                    $data['afternoon_check_in_status'] = 1; // 正常
                }
                break;
                
            case 4: // 下午下班
                $data['afternoon_check_out'] = $currentTime;
                if ($currentTime < $setting['afternoon_end_time']) {
                    $data['afternoon_check_out_status'] = 2; // 早退
                } else {
                    $data['afternoon_check_out_status'] = 1; // 正常
                }
                break;
        }
        
        Db::name('attendance_record')->insert($data);
    }
    
    /**
     * 更新考勤记录
     */
    private function updateAttendanceRecord($record, $checkType, $currentTime, $location, $locationName, $distance, $setting)
    {
        $updateData = [
            'location' => $location,
            'location_name' => $locationName,
            'distance' => $distance,
            'update_time' => date('Y-m-d H:i:s')
        ];
        
        // 根据打卡类型更新对应时间和状态
        switch ($checkType) {
            case 1: // 上午上班
                $updateData['morning_check_in'] = $currentTime;
                if ($currentTime > $setting['morning_start_time']) {
                    $updateData['morning_check_in_status'] = 2; // 迟到
                } else {
                    $updateData['morning_check_in_status'] = 1; // 正常
                }
                break;
                
            case 2: // 上午下班
                $updateData['morning_check_out'] = $currentTime;
                $targetTime = $setting['work_type'] == 1 ? $setting['morning_end_time'] : $setting['morning_end_time'];
                if ($currentTime < $targetTime) {
                    $updateData['morning_check_out_status'] = 2; // 早退
                } else {
                    $updateData['morning_check_out_status'] = 1; // 正常
                }
                break;
                
            case 3: // 下午上班
                $updateData['afternoon_check_in'] = $currentTime;
                if ($currentTime > $setting['afternoon_start_time']) {
                    $updateData['afternoon_check_in_status'] = 2; // 迟到
                } else {
                    $updateData['afternoon_check_in_status'] = 1; // 正常
                }
                break;
                
            case 4: // 下午下班
                $updateData['afternoon_check_out'] = $currentTime;
                if ($currentTime < $setting['afternoon_end_time']) {
                    $updateData['afternoon_check_out_status'] = 2; // 早退
                } else {
                    $updateData['afternoon_check_out_status'] = 1; // 正常
                }
                break;
        }
        
        Db::name('attendance_record')
            ->where('id', $record['id'])
            ->update($updateData);
    }
    
    /**
     * 计算月度统计
     */
    private function calculateMonthlyStats($userId, $year, $month)
    {
        // 获取该月的所有考勤记录
        $startDate = sprintf('%04d-%02d-01', $year, $month);
        $endDate = date('Y-m-t', strtotime($startDate));
        
        $records = Db::name('attendance_record')
            ->where('user_id', $userId)
            ->where('check_date', 'between', [$startDate, $endDate])
            ->select();
        
        // 获取请假记录
        $leaveRecords = Db::name('leave_record')
            ->where('user_id', $userId)
            ->where('status', 1)
            ->where(function($query) use ($startDate, $endDate) {
                $query->whereOr([
                    ['start_date', 'between', [$startDate, $endDate]],
                    ['end_date', 'between', [$startDate, $endDate]],
                    [['start_date', '<=', $startDate], ['end_date', '>=', $endDate]]
                ]);
            })
            ->select();
        
        // 计算工作日天数（这里简化处理，实际应该排除周末和法定节假日）
        $workDays = $this->getWorkDaysInMonth($year, $month);
        
        // 计算各项统计
        $actualDays = count($records);
        $lateTimes = 0;
        $earlyTimes = 0;
        $normalDays = 0;
        
        foreach ($records as $record) {
            // 统计正常出勤天数：所有打卡时间都是正常状态(1)的天数
            $allNormal = true;
            $hasAnyPunch = false;
            
            // 检查每个时间段的状态
            $timeFields = [
                'morning_check_in_status',
                'morning_check_out_status',
                'afternoon_check_in_status', 
                'afternoon_check_out_status'
            ];
            
            foreach ($timeFields as $field) {
                if (!empty($record[$field])) {
                    $hasAnyPunch = true;
                    if ($record[$field] != 1) {
                        $allNormal = false;
                    }
                    
                    // 根据字段类型区分迟到和早退
                    if ($record[$field] == 2) {
                        if (strpos($field, 'check_in') !== false) {
                            // 上班打卡状态2表示迟到
                            $lateTimes++;
                        } elseif (strpos($field, 'check_out') !== false) {
                            // 下班打卡状态2表示早退
                            $earlyTimes++;
                        }
                    }
                }
            }
            
            // 如果有打卡且所有打卡都是正常状态，则算作正常出勤天数
            if ($hasAnyPunch && $allNormal) {
                $normalDays++;
            }
        }
        
        // 计算请假天数
        $leaveDays = 0;
        foreach ($leaveRecords as $leave) {
            $leaveStart = max($leave['start_date'], $startDate);
            $leaveEnd = min($leave['end_date'], $endDate);
            $days = (strtotime($leaveEnd) - strtotime($leaveStart)) / 86400 + 1;
            $leaveDays += $days;
        }
        
        // 计算旷工天数
        $absentDays = $workDays - $actualDays - $leaveDays;
        $absentDays = max(0, $absentDays); // 确保不为负数
        
        return [
            'user_id' => $userId,
            'year' => $year,
            'month' => $month,
            'work_days' => $workDays,
            'actual_days' => $actualDays,
            'late_times' => $lateTimes,
            'early_times' => $earlyTimes,
            'absent_days' => $absentDays,
            'leave_days' => $leaveDays,
            'normal_days' => $normalDays
        ];
    }
    
    /**
     * 获取某月的工作日天数（简化版本）
     */
    private function getWorkDaysInMonth($year, $month)
    {
        $startDate = sprintf('%04d-%02d-01', $year, $month);
        $endDate = date('Y-m-t', strtotime($startDate));
        
        $workDays = 0;
        $current = strtotime($startDate);
        $end = strtotime($endDate);
        
        while ($current <= $end) {
            $dayOfWeek = date('w', $current);
            if ($dayOfWeek != 0 && $dayOfWeek != 6) { // 排除周末
                $workDays++;
            }
            $current = strtotime('+1 day', $current);
        }
        
        return $workDays;
    }
}